home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgramD2.iso
/
Borland
/
Borland C++ V5.02
/
BDTOTAB.PAK
/
OWLTAB.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-06
|
17KB
|
575 lines
// (C) Copyright 1996, Borland International
//
// Owltab.cpp - VDBT Ttable example
/*******************************************************************************
This example demonstrates how hook up to a database table and then
navigate through it using the VDBT Ttable object. The user can navigate
through the table using the Main Menu items or via the keyboard. Only one
record will be displayed at a time.
SETTING UP TO USE AN EVENT HANDLER
Visual Database Tools uses event sources and event sinks (or
handlers) to encapsulate everything necessary for repsonding
to event. The general steps are:
1. Identify the source that will be the source of the events
you wish to handle, in this particular example, TDataSource. This is
done in the MainCreateMsg function.
2. Define the event sink to handle the event. This is done as part of
the EventHandler class.
3. Connect the event sink to the event handler. This is done as part of
The EventHandle constructor.
4. Connect the event source to the event sink. This is done in the
MainCreateMsg function.
The BIOLIFE table in the diveplan database is used by default. A different
database and table can be specified on as command line arguments.
The files needed to build this program are:
owltab.cpp Source file for application
owltab.rc Resource file for application
owltab.ico Icon file for application
owltab16/32.def def file for 16bit target and 32bit target respectively
makefile command-line build file
owltab.ide BCW 5.0 project file for both the 16bit and 32bit target
*******************************************************************************/
#include <vdbt\bdto.h>
#include <windowsx.h>
#include "resource.h"
//******************************************************************************
#define NOTUSED( x ) ((void)(long) (x))
#define DATABASENAME "DivePlan"
#define TABLENAME "biolife.db"
#define MAIN_CLASS_NAME "Main Class"
//******************************************************************************
// function prototypes
BOOL RegisterMainClass( HINSTANCE hInstance );
HWND CreateMainWindow( HINSTANCE hInstance, LPSTR lpszCmdLine, int cmdShow );
extern "C" LRESULT CALLBACK _export MainWndProc( HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam );
void MainCreateMsg( HWND hwnd, LPSTR lpszCmdLine );
void MainPaintMsg( HWND hwnd );
void GetAndDrawGraphic( HDC hdc, TGraphicField& graphic, int x, int y,
int w, int h );
void GetAndDisplayMemo( HDC hdc, TMemoField& memo,int top, int width,
int height );
void DrawPrettyText( HDC hdc, string PrintString, int left, int top, int width,
int height );
BOOL MainCommandMsg( HWND hwnd, WPARAM wParam, LPARAM lParam );
void MainKeyDownMsg( HWND hwnd, WPARAM wParam );
void MainDestroyMsg( HWND hwnd );
#define EXTRA sizeof(TTable*) + sizeof(TDataSource*) + sizeof(EventHandler*)
#define SWL_TABLE 0
#define SWL_DATASOURCE 4
#define SWL_EVENTHANDLER 8
/*******************************************************************************
EventHandler
This is the class that will handle the events that are generated
by the TDataSource object. OnDataChangeSink is the sink for the
OnDataChangeEvent and the OnDataChange method will process all
events passed to OnDataChangeSink by the TDataSource
OnDataChangeSource object.
*******************************************************************************/
class EventHandler
{
private:
HWND hwnd;
public:
EventHandler( HWND h );
// define the event sink to handle the event. This is step #2 of
// setting up to use an event handler for a VDBT event.
TDataChangeSink OnDataChangeSink;
protected:
void OnDataChange(TDataChangeSink& sink, TDataSource& sender, TField* field);
};
// the OnDataChangeSink constructor connects OnDataChangeSink with the
// event handler OnDataChange. This performs stepd #3 for setting up
// to use an event handler for a VDBT event.
EventHandler::EventHandler( HWND h ):
OnDataChangeSink( TDataChange_MFUNCTOR( *this, &EventHandler::OnDataChange ) )
{
hwnd = h;
}
/*******************************************************************************
OnDataChange
When the data changes (the user has navigated to a new record)
invalidate the right hand side of the window and force a repaint.
The left hand side of the windows does not need to be repainted
because it holds data the is static the entire time the app is
running.
*******************************************************************************/
void EventHandler::OnDataChange( TDataChangeSink&, TDataSource&, TField* )
{
if (hwnd)
{
RECT rc;
GetClientRect( hwnd, &rc );
rc.left = rc.right/2;
InvalidateRect( hwnd, &rc, TRUE );
}
}
//******************************************************************************
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int cmdShow )
{
if (! hPrevInstance)
if (! RegisterMainClass(hInstance))
return 0;
CreateMainWindow(hInstance, lpszCmdLine, cmdShow);
MSG msg;
while (GetMessage(&msg, (HWND) 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//******************************************************************************
BOOL RegisterMainClass( HINSTANCE hInstance )
{
WNDCLASS wndClass;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = MainWndProc;
wndClass.cbClsExtra = 0;
// allocate extra memor to hold the table, datasource and event handler
// pointers.
wndClass.cbWndExtra = EXTRA;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
wndClass.hCursor = LoadCursor((HINSTANCE) 0, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wndClass.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN);
wndClass.lpszClassName = MAIN_CLASS_NAME;
return RegisterClass(&wndClass);
}
//******************************************************************************
HWND CreateMainWindow( HINSTANCE hInstance, LPSTR lpszCmdLine, int cmdShow )
{
char szTitle[30 + 1];
HWND hwnd;
LoadString(hInstance, IDS_MAINTITLE, szTitle, 30);
hwnd = CreateWindow(MAIN_CLASS_NAME, szTitle, WS_TILEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
(HWND) 0, (HMENU) 0, hInstance, lpszCmdLine);
if (hwnd)
{
ShowWindow(hwnd, cmdShow);
UpdateWindow(hwnd);
}
return hwnd;
}
//******************************************************************************
extern "C" LRESULT CALLBACK _export MainWndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
MainCreateMsg( hwnd, (LPSTR)((LPCREATESTRUCT) lParam)->lpCreateParams);
break;
case WM_PAINT:
MainPaintMsg(hwnd);
break;
case WM_COMMAND:
if (! MainCommandMsg(hwnd, wParam, lParam))
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
case WM_KEYDOWN:
MainKeyDownMsg(hwnd, wParam);
break;
case WM_DESTROY:
MainDestroyMsg(hwnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0L;
}
/*******************************************************************************
MainCreateMsg.
This initializes the main window and the database table. Things
to note are the create of the TTable object, the try block that
opens the database table, the create of the datasource object
and the attachment to the OnDataChange event.
*******************************************************************************/
void MainCreateMsg(HWND hwnd, LPSTR lpszCmdLine)
{
// Parse the command line for the alias and table names.
LPSTR databaseName = DATABASENAME;
LPSTR tableName = TABLENAME;
if (*lpszCmdLine)
{
LPSTR space = strchr( lpszCmdLine, ' ');
if (space)
{
*space = '\0';
tableName = space+1;
databaseName = lpszCmdLine;
}
}
// Update the window's title bar with the database and table names.
char szTitle[30 + 100 + 1];
int len = GetWindowText( hwnd, szTitle, sizeof(szTitle) );
wsprintf( szTitle+len, " - :%s:%s", databaseName, tableName );
SetWindowText( hwnd, szTitle );
// Create the TTable object. This is the step #1 for setting up to use
// an event handler for a VDBT event.
TTable* table = new TTable;
if (table)
{
// Put the database and table name properties, open the table.
try
{
table->DatabaseName = string( databaseName );
table->TableName = string( tableName );
table->Open();
}
catch (BDTException e)
{
e.Show( "processing WM_CREATE" );
delete table;
table = NULL;
}
// put the pointer to the table object to the 0 offset (SWL_TABLE=0) of
// the extra window memory of hwnd.
SetWindowLong( hwnd, SWL_TABLE, (LONG) table );
if (table)
{
// Create a datasource object and attach to the OnDataChange event.
EventHandler* handler = new EventHandler( hwnd );
if (handler)
{
TDataSource* datasource = new TDataSource;
if (datasource)
{
datasource->DataSet = table;
// The following line connects the event source,
// datasource->OnDataChangeSource to the event sink,
// handler->OnDataChangeSink. The is the fourth and final step
// for setting up to use an event handler for a VDBT event.
datasource->OnDataChangeSource += handler->OnDataChangeSink;
// put the pointer to the datasource object to the 4 offset
// (SWL_DATASOURCE=4) of the extra window memory of hwnd.
SetWindowLong( hwnd, SWL_DATASOURCE, (LONG) datasource );
}
// put the pointer to the event handler object to the 8 offset
// (SWL_EVENTHANDLER=8) of the extra window memory of hwnd.
SetWindowLong( hwnd, SWL_EVENTHANDLER, (LONG) handler );
}
}
}
}
/*******************************************************************************
MainPaintMsg
This function will repaint the window with the (static) table field
names on the left side and the (dynamic) field entries on the right.
*******************************************************************************/
void MainPaintMsg(HWND hwnd)
{
PAINTSTRUCT ps;
RECT rc;
BeginPaint( hwnd, &ps );
GetClientRect( hwnd, &rc );
// Retrieve the pointer to the table from the extra memory in hwnd
TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
if (table)
{
int count = table->FieldCount;
if (count)
{
int width = rc.right/2;
int height = rc.bottom/count;
// Paint the field names on the left side of the window, the
// field values on the right side of the window.
int i;
for (i = 0; i < count; i++)
{
string s = table->Fields[i]->FieldName;
DrawPrettyText( ps.hdc, s, 0, i*height, width, height );
if (table->Fields[i]->DataType == ftGraphic)
{
GetAndDrawGraphic( ps.hdc, TGraphicField(table->Fields[i]),
width, i*height, width, height );
}
else if (table->Fields[i]->DataType ==ftMemo)
{
GetAndDisplayMemo( ps.hdc, TMemoField(table->Fields[i]),
i*height, width, height );
}
else
{
s = table->Fields[i]->Text;
DrawPrettyText( ps.hdc, s, width, i*height, width, height );
}
}
}
}
EndPaint(hwnd, &ps);
}
/*******************************************************************************
GetAndDrawGraphic
This will function will accurately display a graphic field that is
in the current record. Note that the SaveToBitmap method will
save the bitmap from the graphic field to the hbitmap and hpalette
handles.
*******************************************************************************/
void GetAndDrawGraphic( HDC hdc, TGraphicField& graphic, int x, int y, int w,
int h )
{
// Use the SaveToBitmap method to get the bitmap and palette handles.
HBITMAP hbm = 0;
HPALETTE hpal = 0;
graphic.SaveToBitmap( hbm, hpal );
if (hbm)
{
HDC hdcTemp = CreateCompatibleDC( hdc );
if (hdcTemp)
{
BITMAP bm;
GetObject( hbm, sizeof(BITMAP), &bm );
HBITMAP hbmPrev = SelectBitmap( hdcTemp, hbm );
StretchBlt( hdc, x, y, w, h,
hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
SelectBitmap( hdcTemp, hbmPrev );
DeleteDC( hdcTemp );
}
DeleteBitmap( hbm );
}
if (hpal)
DeletePalette( hpal );
}
/*******************************************************************************
GetAndDisplayMemo
This function will accurately display a memo field that is
in the current record. Note that the DrawPrettyText function will
perform word-wrap so that as much of the memo as possible will be
displayed.
*******************************************************************************/
void GetAndDisplayMemo( HDC hdc, TMemoField& memo, int top, int width,
int height)
{
TMemoryStream stream;
memo.SaveToStream( stream );
stream.Position = 0;
TStrings strings;
strings.LoadFromStream( stream );
string s = strings.Text;
DrawPrettyText( hdc, s, width, top, width, height );
}
/*******************************************************************************
DrawPrettyText
function will use DrawText to perform word-wrap so that as much of
text to be displayed as possible is actually displayed in the available
rectangle.
*******************************************************************************/
void DrawPrettyText( HDC hdc, string PrintString, int left, int top, int width,
int height )
{
RECT rc;
rc.left = left;
rc.top = top;
rc.right = rc.left + width;
rc.bottom = rc.top + height;
DrawText(hdc, PrintString.c_str(), PrintString.length(), &rc,
DT_TOP | DT_LEFT | DT_WORDBREAK | DT_NOPREFIX );
}
/*******************************************************************************
MainCommandMsg
This handles all of the commands that come for the Main Menu
to navigate through the table. All other WM_COMMAND messages are
passed onto Windows.
*******************************************************************************/
BOOL MainCommandMsg(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
NOTUSED( lParam );
// Process navigation commands from the menu.
TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
if (table)
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDM_NAV_FIRST:
table->First();
break;
case IDM_NAV_PRIORSET:
table->MoveBy(-5);
break;
case IDM_NAV_PRIOR:
table->Prior();
break;
case IDM_NAV_NEXT:
table->Next();
break;
case IDM_NAV_NEXTSET:
table->MoveBy(5);
break;
case IDM_NAV_LAST:
table->Last();
break;
default:
return FALSE;
}
return TRUE;
}
return FALSE;
}
/*******************************************************************************
MainKeyDownMsg
This handle all of the keyboard messages that will be used to navigate
the table. All other WM_KEYDOWN messages are passed onto Windows.
*******************************************************************************/
void MainKeyDownMsg(HWND hwnd, WPARAM wParam)
{
// Process navigation commands from the keyboard.
TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
if (table)
{
switch (wParam)
{
case VK_HOME:
table->First();
break;
case VK_PRIOR:
table->MoveBy(-5);
break;
case VK_UP:
table->Prior();
break;
case VK_DOWN:
table->Next();
break;
case VK_NEXT:
table->MoveBy(5);
break;
case VK_END:
table->Last();
break;
}
}
}
/*******************************************************************************
MainDestroyMsg
This destroys the datasource object, the handler object and then the
table object.
*******************************************************************************/
void MainDestroyMsg( HWND hwnd )
{
// Delete the table and the datasource.
// Retrieve the pointer to the table from the extra memory in hwnd
// and then clear the entry.
TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
SetWindowLong( hwnd, SWL_TABLE, 0 );
if (table)
{
// Retrieve the pointer to the datasource from the extra memory in hwnd
// and then clear the entry.
TDataSource* datasource=(TDataSource*)GetWindowLong(hwnd, SWL_DATASOURCE);
SetWindowLong( hwnd, SWL_DATASOURCE, 0 );
if (datasource)
delete datasource;
// Retrieve the pointer to the event handler from the extra memory
// in hwnd and then clear the entry.
EventHandler* handler=(EventHandler*)GetWindowLong(hwnd, SWL_EVENTHANDLER);
SetWindowLong( hwnd, SWL_EVENTHANDLER, 0 );
if (handler)
delete handler;
delete table;
}
}